#include "U2TestRenderable.h"

#include "U2VertexIndexData.h"
#include "U2HardwareBufferManager.h"
#include "U2TextureManager.h"
#include "U2Root.h"
#include "U2RenderSystem.h"
#include "U2TextureUnitState.h"


U2EG_NAMESPACE_USING


// vertex buffer bindings, set at compile time (we could look these up but no point)
#define POSITION_BINDING                0
#define COLOUR_BINDING                  1
#define TEXCOORD_BINDING                2


U2TestRenderable::U2TestRenderable() 
: mU1(0.0f)
, mV1(0.0f)
, mU2(1.0f)
, mV2(1.0f)
, m_pt(NULL)
{
    initialise2();
    //updatePositionGeometry();
    //updateTextureGeometry();
}

U2TestRenderable::~U2TestRenderable()
{

}

void U2TestRenderable::initialise(void)
{
    // Setup render op in advance
    mRenderOp.vertexData = U2_NEW U2VertexData();
    // Vertex declaration: 1 position, add texcoords later depending on #layers
    // Create as separate buffers so we can lock & discard separately
    U2VertexDeclaration* decl = mRenderOp.vertexData->vertexDeclaration;
    size_t nOffset = 0;
    decl->addElement(POSITION_BINDING, nOffset, VET_FLOAT3, VES_POSITION);
    nOffset += U2VertexElement::getTypeSize(VET_FLOAT3);
    decl->addElement(POSITION_BINDING, nOffset, VET_FLOAT2, VES_TEXTURE_COORDINATES);
    nOffset += U2VertexElement::getTypeSize(VET_FLOAT2);

    // Basic vertex data
    mRenderOp.vertexData->vertexStart = 0;
    mRenderOp.vertexData->vertexCount = 4;

    // Vertex buffer #1
    U2HardwareVertexBufferSharedPtr vbuf =
        U2HardwareBufferManager::getSingleton().createVertexBuffer(
        decl->getVertexSize(POSITION_BINDING), mRenderOp.vertexData->vertexCount,
        U2HardwareBuffer::HBU_STATIC_WRITE_ONLY// mostly static except during resizing
        );
    // Bind buffer
    mRenderOp.vertexData->vertexBufferBinding->setBinding(POSITION_BINDING, vbuf);

    // No indexes & issue as a strip
    mRenderOp.useIndexes = false;
    mRenderOp.operationType = U2RenderOperation::OT_TRIANGLE_STRIP;
    mRenderOp.useGlobalInstancingVertexBufferIsAvailable = false;

    /*
    // NB reference counting will take care of the old one if it exists
    U2HardwareVertexBufferSharedPtr newbuf =
        U2HardwareBufferManager::getSingleton().createVertexBuffer(
        decl->getVertexSize(TEXCOORD_BINDING), mRenderOp.vertexData->vertexCount,
        U2HardwareBuffer::HBU_STATIC_WRITE_ONLY // mostly static except during resizing
        );
    // Bind buffer, note this will unbind the old one and destroy the buffer it had
    mRenderOp.vertexData->vertexBufferBinding->setBinding(TEXCOORD_BINDING, newbuf);
    */

    mTex = U2TextureManager::getSingletonPtr()->load("nehe.png", "General");
    U2Root::getSingletonPtr()->getRenderSystem()->_setTexture(0, true, mTex);
}

void U2TestRenderable::updatePositionGeometry(void)
{
	/*
		0-----2
		|    /|
		|  /  |
		|/    |
		1-----3
	*/
	u2real left, right, top, bottom;

	/* Convert positions into -1, 1 coordinate space (homogenous clip space).
		- Left / right is simple range conversion
		- Top / bottom also need inverting since y is upside down - this means
		that top will end up greater than bottom and when computing texture
		coordinates, we have to flip the v-axis (ie. subtract the value from
		1.0 to get the actual correct value).
	*/
// 	left = _getDerivedLeft() * 2 - 1;
// 	right = left + (mWidth * 2);
// 	top = -((_getDerivedTop() * 2) - 1);
// 	bottom =  top -  (mHeight * 2);
    left = -10.0f;
    right = 10.0f;
    top = 10.0f;
    bottom = -10.0f;

	U2HardwareVertexBufferSharedPtr vbuf =
		mRenderOp.vertexData->vertexBufferBinding->getBuffer(POSITION_BINDING);
	float* pPos = static_cast<float*>(
		vbuf->lock(U2HardwareBuffer::HBL_DISCARD) );

	// Use the furthest away depth value, since materials should have depth-check off
	// This initialised the depth buffer for any 3D objects in front
	//u2real zValue = Root::getSingleton().getRenderSystem()->getMaximumDepthInputValue();
    u2real zValue = 0.0f;
	*pPos++ = left;
	*pPos++ = top;
	*pPos++ = zValue;
    pPos += U2VertexElement::getTypeSize(VET_FLOAT2);

	*pPos++ = left;
	*pPos++ = bottom;
	*pPos++ = zValue;
    pPos += U2VertexElement::getTypeSize(VET_FLOAT2);

	*pPos++ = right;
	*pPos++ = top;
	*pPos++ = -zValue;
    pPos += U2VertexElement::getTypeSize(VET_FLOAT2);

	*pPos++ = right;
	*pPos++ = bottom;
	*pPos++ = -zValue;

	vbuf->unlock();
}

void U2TestRenderable::updateTextureGeometry(void)
{
    U2VertexDeclaration* decl = mRenderOp.vertexData->vertexDeclaration;
    U2HardwareVertexBufferSharedPtr vbuf =
		mRenderOp.vertexData->vertexBufferBinding->getBuffer(POSITION_BINDING);
	float* pVBStart = static_cast<float*>(
		vbuf->lock(U2HardwareBuffer::HBL_DISCARD) );

	size_t uvSize = U2VertexElement::getTypeSize(VET_FLOAT2) / sizeof(float);
	size_t vertexSize = decl->getVertexSize(POSITION_BINDING) / sizeof(float);
	for (u2ushort i = 0; i < 1; ++i)
	{
	    // Calc upper tex coords
//         u2real upperX = mU2 * mTileX[i];
//         u2real upperY = mV2 * mTileY[i];


	    /*
		    0-----2
		    |    /|
		    |  /  |
		    |/    |
		    1-----3
	    */
	    // Find start offset for this set
	    float* pTex = pVBStart + (i * decl->getVertexSize(POSITION_BINDING) * mRenderOp.vertexData->vertexCount);

        pTex += U2VertexElement::getTypeSize(VET_FLOAT3);
        *pTex++ = mU1;
        *pTex++ = mV1;

        pTex += U2VertexElement::getTypeSize(VET_FLOAT3);
        *pTex++ = mU1;
        *pTex++ = mV2;

        pTex += U2VertexElement::getTypeSize(VET_FLOAT3);
        *pTex++ = mU2;
        *pTex++ = mV1;

        pTex += U2VertexElement::getTypeSize(VET_FLOAT3);
        *pTex++ = mU2;
        *pTex++ = mV2;
	}
	vbuf->unlock();
}

void U2TestRenderable::getRenderOperation(U2RenderOperation& op)
{
    op = mRenderOp;
}

void U2TestRenderable::initialise2(void)
{
    // Setup render op in advance
    mRenderOp.vertexData = U2_NEW U2VertexData();
    // Vertex declaration: 1 position, add texcoords later depending on #layers
    // Create as separate buffers so we can lock & discard separately
    U2VertexDeclaration* decl = mRenderOp.vertexData->vertexDeclaration;
    size_t nOffset = 0;
    decl->addElement(POSITION_BINDING, nOffset, VET_FLOAT3, VES_POSITION);
    nOffset += U2VertexElement::getTypeSize(VET_FLOAT3);
//     decl->addElement(POSITION_BINDING, nOffset, VET_COLOUR, VES_DIFFUSE);
//     nOffset += U2VertexElement::getTypeSize(VET_COLOUR);

    // Basic vertex data
    mRenderOp.vertexData->vertexStart = 0;
    mRenderOp.vertexData->vertexCount = 3;

    // Vertex buffer #1
    U2HardwareVertexBufferSharedPtr vbuf =
        U2HardwareBufferManager::getSingleton().createVertexBuffer(
        nOffset/*decl->getVertexSize(POSITION_BINDING)*/, mRenderOp.vertexData->vertexCount,
        U2HardwareBuffer::HBU_STATIC_WRITE_ONLY// mostly static except during resizing
        );

    /*
    const size_t vbufCount = 3 * (3 + 4); 
    float vertices[vbufCount] = { 
        -1.0, 1.0, -0.0,        //0 position 
        0, 128.0, 0, 255,          //0 color 
        1.0, 1.0, -0.0,         //1 position 
        0, 128.0, 0, 255,          //1 color 
        0.0, -1.0, 0.0,        //2 position 
        0, 128.0, 0, 255,          //2 color 
    };
    */
    const size_t vbufCount = 3 * (3); 
    float vertices[vbufCount] = { 
        -1.0, 1.0, -0.0,        //0 position 
        0.0, -1.0, 0.0,         //1 position 
        1.0, 1.0, -0.0,         //2 position 
    };
    
    vbuf->writeData(0, vbuf->getSizeInBytes(), vertices, true); 

    // Bind buffer
    mRenderOp.vertexData->vertexBufferBinding->setBinding(POSITION_BINDING, vbuf);

    /*
    nOffset = 0;
    const U2VertexElement& vElem = decl->addElement(COLOUR_BINDING, nOffset, VET_COLOUR, VES_DIFFUSE);
    nOffset += U2VertexElement::getTypeSize(VET_COLOUR);

    vbuf =
        U2HardwareBufferManager::getSingleton().createVertexBuffer(
        nOffset, mRenderOp.vertexData->vertexCount,
        U2HardwareBuffer::HBU_STATIC_WRITE_ONLY// mostly static except during resizing
        );

    //U2RenderSystem* rs = U2Root::getSingleton().getRenderSystem(); 
    const size_t colourCount = 3; 
    RGBA colours[colourCount];
    RGBA *pColour = colours;
    colours[0] = vElem.convertColourValue(U2ColourValue(1.0, 0.0, 0.0), VET_COLOUR_ARGB);    //0 colour
    colours[1] = vElem.convertColourValue(U2ColourValue(0.0, 1.0, 0.0), VET_COLOUR_ARGB);    //0 colour
    colours[2] = vElem.convertColourValue(U2ColourValue(0.0, 0.0, 1.0), VET_COLOUR_ARGB);    //0 colour

    vbuf->writeData(0, vbuf->getSizeInBytes(), colours, true); 

    // Bind buffer
    mRenderOp.vertexData->vertexBufferBinding->setBinding(COLOUR_BINDING, vbuf);
    */

    
    nOffset = 0;
    decl->addElement(TEXCOORD_BINDING, nOffset, VET_FLOAT2, VES_TEXTURE_COORDINATES);
    nOffset += U2VertexElement::getTypeSize(VET_FLOAT2);

    vbuf =
        U2HardwareBufferManager::getSingleton().createVertexBuffer(
        nOffset, mRenderOp.vertexData->vertexCount,
        U2HardwareBuffer::HBU_STATIC_WRITE_ONLY// mostly static except during resizing
        );

    const size_t texCoorCount = 3 * (2); 
    float texCoors[texCoorCount] = { 
        0.0f, 0.0f,         //0 position 
        0.5f, 1.0f,         //1 position 
        1.0f, 0.0f,         //2 position 
    };

    vbuf->writeData(0, vbuf->getSizeInBytes(), texCoors, false); 

    // Bind buffer
    mRenderOp.vertexData->vertexBufferBinding->setBinding(TEXCOORD_BINDING, vbuf);
    
    

    // No indexes & issue as a strip
    mRenderOp.useIndexes = false;
    mRenderOp.operationType = U2RenderOperation::OT_TRIANGLE_LIST;
    mRenderOp.useGlobalInstancingVertexBufferIsAvailable = false;


    
    mTex = U2TextureManager::getSingletonPtr()->load("NeHe.bmp", "General");
    //U2Root::getSingletonPtr()->getRenderSystem()->_setTexture(0, true, mTex);

    m_pt = U2_NEW TextureUnitState("General");
    m_pt->setTextureName("NeHe.bmp");
    //t->setTextureCoordSet(texCoordSet);
     
}

TextureUnitState* U2TestRenderable::getTextureUnitState()
{
    return m_pt;
}